package mylab.utils.common;

import org.reflections.Reflections;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.hutool.core.lang.Assert;
import lombok.experimental.UtilityClass;


@UtilityClass
public class ReflectUtil extends cn.hutool.core.util.ReflectUtil {

    /**
     * 查找所有子类
     *
     * @param prefix     全类名前缀
     * @param superClass 父类
     * @param <T>        父类类型
     * @return 所有子类
     */
    public <T> Set<Class<? extends T>> getSubTypesOf(String prefix, Class<T> superClass) {
        if (prefix == null) {
            prefix = PackageUtil.getAppBasePackageName();
        }
        Reflections reflections = new Reflections(prefix);
        return reflections.getSubTypesOf(superClass);
    }

    /**
     * 获取目标类型的所有字段
     *
     * @param clazz 目标类型
     * @param <T>   泛型类型
     * @return 字段列表
     */
    public <T> List<Field> getAllField(Class<T> clazz) {
        List<Field> fieldList = new ArrayList<>();
        Class<?> tempClass = clazz;
        while (tempClass != null) {
            //当父类为null的时候说明到达了最上层的父类(Object类)
            fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
            //得到父类,然后赋给自己
            tempClass = tempClass.getSuperclass();
        }
        return fieldList;
    }

    /**
     * 获取目标类型的所有字段（按继承顺序）
     *
     * @param clazz 目标类型
     * @param <T>   泛型类型
     * @return 字段列表
     */
    public <T> List<Field> getAllFieldByOrder(Class<T> clazz) {
        List<Field> list = new ArrayList<>();
        Class<?> tempClass = clazz;
        while (tempClass != null) {
            list.addAll(0, Arrays.asList(tempClass.getDeclaredFields()));
            //得到父类,然后赋给自己
            tempClass = tempClass.getSuperclass();
        }
        return list;
    }

    /**
     * 获取目标类型中有指定注解标记的字段列表
     *
     * @param clazz           目标类型
     * @param annotationClass 指定注解
     * @return 字段列表
     */
    public List<Field> getAllFieldByAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        List<Field> list = new ArrayList<>();
        Class<?> tempClass = clazz;
        while (tempClass != null) {

            list.addAll(Stream.of(tempClass.getDeclaredFields())
                    .filter(field -> field.isAnnotationPresent(annotationClass))
                    .collect(Collectors.toSet()));
            //得到父类,然后赋给自己
            tempClass = tempClass.getSuperclass();
        }
        return list;
    }

    /**
     * 根据类名生成实例，支持有默认构造方法或单子模式（限定包含getInstance方法）
     *
     * @param classFullName 完整类名
     * @param <T>           泛型类型
     * @return 实例
     */
    public <T> T toInstance(String classFullName) {
        Assert.notNull(classFullName, "classFullName is null");
        try {
            Class<?> clazz = Class.forName(classFullName);
            return toInstance(clazz);
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }

        return null;
    }

    public <T> T toInstance(Class<?> clazz) {
        Assert.notNull(clazz, "clazz is null");
        Object obj = null;

        try {
            Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
            defaultConstructor.setAccessible(true);
            obj = defaultConstructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }

        return CastUtil.cast(obj);
    }

    /**
     * 获取列表的泛型类型
     *
     * @param list 列表
     * @param <T>  泛型类型
     * @return 泛型类型
     */
    public <T> Class<?> getGenericType(List<T> list) {
        return list.toArray().getClass().getComponentType();
    }

    /**
     * 获取集合的泛型类型
     *
     * @param collection 集合
     * @param <T>        泛型类型
     * @return 泛型类型
     */
    public <T> Class<?> getGenericType(Collection<T> collection) {
        return collection.toArray().getClass().getComponentType();
    }

    /**
     * 获取目标类型的父类的第一个泛型参数的类型
     *
     * @param clazz 目标类型
     * @return 参数位置
     */
    public <T> Class<T> getGenericType(Class<?> clazz) {
        return getGenericType(clazz, 0);
    }

    /**
     * 获取目标类型的父类的泛型参数的类型
     * eg: ClassA<T1,T2> 中的 T1 或 T2 的类型
     *
     * @param clazz 目标类型
     * @param index 参数位置
     * @return 参数的类型
     */
    public <T> Class<T> getGenericType(Class<?> clazz, int index) {
        //返回直接继承的父类（包含泛型参数）
        Type type = clazz.getGenericSuperclass();

        // 不是泛型类
        if (!(type instanceof ParameterizedType genType)) {
            return null;
        }

        Type[] types = genType.getActualTypeArguments();

        Assert.isTrue(index >= 0 && index < types.length, "getGenericType: index error");
        Type objType = types[index];

        return CastUtil.cast(objType);
    }
}
